package com.omnisyr.paperanalyser;

import java.awt.Desktop;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.omnisyr.paperanalyser.common.Paper;
import com.omnisyr.paperanalyser.common.SimpleArrayList;

public class PaperAnalyser {

	/**
	 * 
	 * Important: </BR>
	 * Be sure you have downloaded the 47G data-sets to assets/datasets and in SSD.
	 * </BR>
	 * Be sure you have enough CPU cores for searching. </BR>
	 * Be sure you have enough memory. </BR>
	 * </BR>
	 * For i9-14900Hx-24cores-32threads. </BR>
	 * Time costs: 60 ~ 90s. </BR>
	 * RAM costs: ~ 16G. </BR>
	 * 
	 * Search papers which in the data-sets.</BR>
	 * Use different index to search different attribution.</BR>
	 * </BR>
	 * Example: </BR>
	 * To get all papers from Visual Informatics. </BR>
	 * Use: search(5, "Visual Informatics") </BR>
	 * 
	 * @param index  </BR>
	 *               0: Omid or openalex id or doi. </BR>
	 *               1: Title. </BR>
	 *               2: Authors. </BR>
	 *               3: Issue. </BR>
	 *               4: Volume. </BR>
	 *               5: Venue. </BR>
	 *               6: Page number. </BR>
	 *               7: Date. </BR>
	 *               8: Type. </BR>
	 *               9: Publisher. </BR>
	 * @param target </BR>
	 *               The string contained. </BR>
	 * @return
	 */
	public static ArrayList<Paper> search(int index, String target) {

		list = new ArrayList<Paper>();

		int processors = Runtime.getRuntime().availableProcessors() - 1;
		int amount = 28717 / processors;

		ExecutorService executor = Executors.newCachedThreadPool();// Without a multi-search, it will take a long time.
		File[] files = new File("assets/datasets").listFiles();

		for (int i = 0; i < processors; i++) {// Deliver jobs.

			int a = i;

			if (i != processors - 1) {

				executor.execute(() -> addPaperToList(a, files, a * amount, (a + 1) * amount, index, target));

			} else {

				executor.execute(() -> addPaperToList(a, files, a * amount, files.length, index, target));

			}

		}

		while (count < 28717) {

			System.err.println(count * 100.0 / 28717 + "%");

			try {

				Thread.sleep(1000);

			} catch (InterruptedException e) {

				e.printStackTrace();

			}

		}

		System.err.println("100%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");// Done.

		return list;

	}

	public static void main(String[] args) {

		search(5, "2468-502X");
		open();

	}

	private static void open() {

		for (Paper paper : list) {

			if (!paper.getDOI().contains("2017")) {// Find the target papers which from 2017.

				continue;

			}

			if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {

				try {

					Desktop.getDesktop().browse(new URI("https://sci-hub.se/" + paper.getDOI()));// Open the webs.

					Thread.sleep(5000);

				} catch (Exception ex) {

				}

			}

		}

	}

	private static int count = 0;

	private static synchronized void add() {

		count++;

	}

	private static ArrayList<Paper> list = new ArrayList<Paper>();

	private static void addPaperToList(int processorID, File[] files, int from, int to, int index,
			String target) {

		try {

			Scanner scanner;

			for (int i = from; i < to; i++) {

				scanner = new Scanner(files[i], "UTF-8");

				while (scanner.hasNext()) {

					String[] strs = scanner.nextLine().split("\",\"");

					if (!isTarget(strs, index, target)) {

						continue;

					}

					Paper paper = new Paper(strs);

					list.add(paper);

				}

				add();

			}

		} catch (Exception ex) {

		}

	}

	private static boolean isTarget(String[] strs, int index, String target) {

		SimpleArrayList<String> list = new SimpleArrayList<String>();

		for (String content : strs) {

			list.add(content);

		}

		String att = list.get(index);

		if (att == null) {

			return false;

		}

		if (att.contains(target)) {

			return true;

		}

		return false;

	}

}
